package com.acme.bankapp.domain;

//want to incapsulate package-local methods of Client and Bank

import com.acme.bankapp.domain.Bank;
import com.acme.bankapp.domain.Client;
import com.acme.bankapp.domain.accounting.Account;
import com.acme.bankapp.services.EmailSender;

public class BankService {
	
	public static final String ACCOUNTS_INFORMATION_REPORT_HEADER = "Accounts";
	public static final String CLIENTS_LIST_REPORT_HEADER = "Bank clients";
	public static final String CLIENTS_ACCOUNTS_REPORT_HEADER = "Clients accounts";
	
	public static final String ADMIN_EMAIL = "admin@email.com";

	/**
	 * Add client to bank
	 * 
	 * @param bank
	 * @param client
	 */
	public void addClient(Bank bank, Client client) {
		bank.addClient(client);
	}

	/**
	 * Add account to client's accounts.
	 * 
	 * @param client
	 *            Client
	 * @param account
	 *            Account
	 */
	public void addAccount(Client client, Account account) {
		client.addAccount(account);
	}

	/**
	 * Deposit to account
	 * 
	 * @param account
	 *            Account
	 * @param x
	 *            Value to deposit
	 */
	public void deposit(Account account, double x) {
		account.deposit(x);
	}

	/**
	 * Withdraw from account
	 * 
	 * @param account
	 *            Account
	 * @param x
	 *            Value to withdraw
	 * @throws LowBalanceException
	 *             Error withdrawing if X is greater than available amount to
	 *             withdraw
	 */
	public void withdraw(Account account, double x) throws Exception {
		account.withdraw(x);
	}

	/**
	 * new bank
	 * 
	 * @return clean bank
	 */
	public Bank createBank() {
		Bank bank = new Bank();

		bank.addClientRegistrationListener(new Bank.ClientRegistrationListener() {
			public void onClientRegistred(Client client) {
				System.out.println("Client: " + client.getClientSalutation()
						+ " was added\n");
			}
		});
		
		bank.addClientRegistrationListener(new Bank.ClientRegistrationListener() {
			public void onClientRegistred(Client client) {
				EmailSender sender = new EmailSender();
				sender.sendEmail(ADMIN_EMAIL,
						"Client: " + client.getClientSalutation()
								+ " was added");

			}
		});
		

		return bank;
	}
	
	
	//[MA] client has package-local constructor
	//service allow creating Client object with public access
	
	/**
	 * Creates client
	 * @param name Client name
 	 * @param gender Client gender
	 * @return Client
	 */
	public Client createClient(String name, Gender gender){
		return new Client(name, gender);
	}


	/**
	 * Bank's clients list report
	 * 
	 * @param bank
	 *            Bank
	 * @return Report
	 */
	public String reportBankClients(Bank bank) {
		StringBuilder builder = new StringBuilder();
		builder.append("\n").append(CLIENTS_LIST_REPORT_HEADER)
				.append("\n");
		for (Client client : bank.getClients()) {
			builder.append(client.getClientSalutation()).append("\n");
		}
		return builder.toString();
	}

	/**
	 * Amounts to withdraw report over all clients
	 * 
	 * @param bank
	 * @return report
	 */
	public String reportAccountsInformation(Bank bank) {
		StringBuilder builder = new StringBuilder();
		builder.append("\n").append(ACCOUNTS_INFORMATION_REPORT_HEADER)
				.append("\n");
		for (Client client : bank.getClients()) {
			builder.append(getAccountsInformation(client));
		}

		return builder.toString();
	}

	/**
	 * Client's account report
	 * 
	 * @param client
	 *            Client
	 * @return report
	 */
	public String reportClientsAccounts(Client client) {
		StringBuilder builder = new StringBuilder();
		builder.append("\n").append(CLIENTS_ACCOUNTS_REPORT_HEADER)
				.append("\n");
		builder.append(getAccountsInformation(client));
		
		return builder.toString();
	}
	
	private String getAccountsInformation(Client client){
		StringBuilder builder = new StringBuilder();
		for (Account account : client.getAccounts()) {
			builder.append(client.getClientSalutation()).append(" ")
					.append(account.getClass().getSimpleName()).append(" : ")
					.append("balance: ").append(account.getBalance())
					.append(" max wihdraw: ")
					.append(account.maximumAmountToWithdraw()).append("\n");
		}
		return builder.toString();		
	}
}
